#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "script_expression.h"
//#include "binary_tree.h"

#include "script_stack.h"

#include "script_string.h"
#include "script_func.h"
#include "script.h"
#include "script_debug.h"
#include "script_memory.h"
#include "script_var.h"

//----------------------------------------

static exp_node_t *exec_func_decode(exp_parser_t *parser,exp_node_t *func_exp);

void get_var_value(exp_var_t *var, exp_node_type_e *type, char **str, int *num,double *d)
{
	switch(var->type){
		case EXP_VAR_TYPE_INT:
			*type = EXP_NODE_TYPE_CONST_INT;
			if(num) *num = var->value;
			break;
		case EXP_VAR_TYPE_DOUBLE:
			*type = EXP_NODE_TYPE_CONST_DOUBLE;
			if(d) *d = var->number;
			break;
		case EXP_VAR_TYPE_STRING:
			*type = EXP_NODE_TYPE_CONST_STRING;
			if(str) *str = var->str;
			break;
		case EXP_VAR_TYPE_POINT:
			get_var_value(var->var,type,str,num,d);
			break;
		case EXP_VAR_TYPE_STRUCT:
			*type = EXP_NODE_TYPE_VAR;
			break;
		case EXP_VAR_TYPE_TRUE:
			*type = EXP_NODE_TYPE_CONST_TRUE;
			break;
		case EXP_VAR_TYPE_FALSE:
			*type = EXP_NODE_TYPE_CONST_FALSE;
			break;
		case EXP_VAR_TYPE_C_VAR:
			switch(var->c_var->type){
				case EXP_VAR_TYPE_INT:
					*type = EXP_NODE_TYPE_CONST_INT;
					if(num) *num = *(int*)var->c_var->value;
					break;
				case EXP_VAR_TYPE_DOUBLE:
					*type = EXP_NODE_TYPE_CONST_INT;
					if(d) *d = *(double*)var->c_var->value;
					break;
				case EXP_VAR_TYPE_STRING:
					*type = EXP_NODE_TYPE_CONST_STRING;
					if(str) *str = var->c_var->value;
					break;
				default:
					break;
			}
			break;
		case EXP_VAR_TYPE_NONE:
		case EXP_VAR_TYPE_STRUCT_MEM:
			*type = EXP_NODE_TYPE_CONST_NULL;
			break;
		default:
			*type = EXP_NODE_TYPE_VAR;
			break;
	}
}

void get_exp_node_value(exp_node_t *node, exp_node_type_e *type, char **str, int *num,double *d)
{
	if (node == NULL) {
		return;
	}

	*type = node->type;
	switch(node->type){
		case EXP_NODE_TYPE_CONST_INT:
			if(num) *num = node->number;
			break;
		case EXP_NODE_TYPE_CONST_DOUBLE:
			if(d) *d = node->d;
			break;
		case EXP_NODE_TYPE_CONST_STRING:
			if(str) *str = node->string;
			break;
		case EXP_NODE_TYPE_VAR:
			get_var_value(node->var,type,str,num,d);
			break;
		case EXP_NODE_TYPE_CONST_TRUE:
		case EXP_NODE_TYPE_CONST_FALSE:
			break;
		default:
			*type = EXP_NODE_TYPE_CONST_NULL;
			break;
	}
}

int exp_node_copy(exp_node_t *det, exp_node_t *src)
{
	if (det == NULL || src == NULL)
	{
		return -1;
	}

	det->type = src->type;
	det->ctrl = src->ctrl;
	switch (det->type)
	{
	case EXP_NODE_TYPE_CONST_INT:
		det->number = src->number;
		break;
	case EXP_NODE_TYPE_CONST_DOUBLE:
		det->d = src->d;
		break;
	case EXP_NODE_TYPE_OPERTOR:
		det->oper = src->oper;
		break;
	case EXP_NODE_TYPE_VAR:
		det->var = det->var;
		break;
	case EXP_NODE_TYPE_CONST_STRING:
		if (src->string)
		{
			det->string = script_calloc(1, strlen(src->string) + 1);
			strcpy(det->string, src->string);
		}
		break;
	}
	return 0;
}

static exp_node_t *struct_array_value_decode(exp_parser_t *parser)
{
	if(parser == NULL){
		return NULL;
	}

	char start_c = parser->c_str->str[0];
	char end_c = 0;
	if(start_c == '['){
		end_c = ']';
	}else if(start_c == '{'){
		end_c = '}';
	}else{
		return NULL;
	}

	unsigned int size = 512;
	char *buf = script_calloc(1,size);
	int count = 0;

	exp_string_t *str = parser->c_str;
	while(str){
		unsigned int len = strlen(buf) + strlen(str->str) + 1;
		if(len > size){
			char *tbuf = script_calloc(1,len + 512);
			strcpy(tbuf,buf);
			script_free(buf);
			buf = tbuf;
		}

		strcat(buf,str->str);
		if(parser->c_str->str[0] == end_c){
			if(count == 0){
				break;
			}
			count--;
		} else if(parser->c_str->str[0] == start_c){
			count++;
		}

		str = str->next;
	}

	parser->c_str = str;

	exp_var_t *ns_var = script_default_func_var_get("NewStruct");
	exp_func_t *exp_func = ns_var->func->func;

	exp_node_t *arg = exp_node_create(EXP_NODE_TYPE_CONST_STRING,buf);
	script_free(buf);

	exec_func_t *ex_func = NULL;
	ex_func = script_func_node_create();
	if(ex_func == NULL){
		return NULL;
	}

	ex_func->func = exp_func;
	TFly_list_add(ex_func->args,arg);

	exp_node_t *exp = exp_node_create(EXP_NODE_TYPE_FUNC,ex_func);
	if(exp == NULL){
		// TODO error handle
	}

	exp->func = ex_func;

	return exp;

}

static exp_node_t *remove_end_exp(exp_parser_t *parser)
{
	if(parser == NULL || parser->exp_list == NULL){
		return NULL;
	}



	exp_node_t *node = parser->exp_list;
	exp_node_t *prev = NULL;
	while(node->next){
		prev = node;
		node = node->next;
	}

	if(prev == NULL){
		parser->exp_list = NULL;
	}else{
		prev->next = NULL;
	}

	parser->cnode = prev;

	return node;

}

int expression_str(exp_parser_t *parser)
{
	if (parser == NULL) {
		return -1;
	}

	int pare_close = 0;
	int bracket_close = 0;

	exp_node_t *node = NULL;
	int ret = 0;

	while(parser->c_str){
		//printf("%s %d %s parser:%p\n",__func__,__LINE__,parser->c_str->str,parser);
		switch (parser->c_str->type) {
			case EXP_STRING_TYPE_NONE:
					printf("\033[32m%s %d bracket count:%d\033[0m\r\n",__func__,__LINE__,parser->bracket_count);
				break;
			case EXP_STRING_TYPE_NUMBER:
				node = script_calloc(1, sizeof(exp_node_t));
				if(strchr(parser->c_str->str,'.')){
					node->type = EXP_NODE_TYPE_CONST_DOUBLE;
					node->d = strtod(parser->c_str->str,NULL);
				}else{
					node->type = EXP_NODE_TYPE_CONST_INT;
					node->number = strtol(parser->c_str->str, NULL, 0);
				}
				break;
			case EXP_STRING_TYPE_STRING:
				node = script_calloc(1, sizeof(exp_node_t));
				if (parser->c_str->str[0] == '"') {	// 字符串常亮
					node->type = EXP_NODE_TYPE_CONST_STRING;
					node->string = script_calloc(1, strlen(parser->c_str->str) + 1);
					strncpy(node->string, parser->c_str->str + 1, strlen(parser->c_str->str) - 2);
				}else if(strcmp(parser->c_str->str,"NULL") == 0){	// 空类型
					node->type = EXP_NODE_TYPE_CONST_NULL;
				}else if(strcmp(parser->c_str->str,"TRUE") == 0){	// true类型
					node->type = EXP_NODE_TYPE_CONST_TRUE;
				}else if(strcmp(parser->c_str->str,"FALSE") == 0){	// false类型
					node->type = EXP_NODE_TYPE_CONST_FALSE;
				} else {		// 变量
					if(parser->dot_flag){
						node->type = EXP_NODE_TYPE_CONST_STRING;
						node->string = script_calloc(1, strlen(parser->c_str->str) + 1);
						strncpy(node->string, parser->c_str->str, strlen(parser->c_str->str));
						parser->dot_flag = 0;
						break;
					}
					node->type = EXP_NODE_TYPE_VAR_NAME;
					//node->var_name = find_var(parser->script,parser->c_str->str);
					node->var_name = script_calloc(1,strlen(parser->c_str->str)+1);
					if (node->var_name == NULL) {
						SCRIPT_DEBUG_ERR("Can't find var %s ", parser->c_str->str);
						goto error;
					}
					strcpy(node->var_name,parser->c_str->str);
				}
				break;
			case EXP_STRING_TYPE_OPERTOR:
				if(parser->c_str->str[0] == ',' ){		// 解析函数参数时，','表示解析完成
					if(parser->exec_func_arg_flag){
						parser->c_str = parser->c_str->next;
						ret = 1;
						goto end;
					}else{
						SCRIPT_DEBUG_ERR("',' can't recognise!");
						return SCRIPT_ERR_SYNTAX;
					}
				}else if(parser->c_str->str[0] == ';'){	
					parser->c_str = parser->c_str->next;
					ret = 1;
					goto end;
				}else if(parser->c_str->str[0] == '.'){ // 标记 "." 运算符，下一个节点将解析为字符串
					parser->dot_flag = 1;
				}

				// = 后面是 [] {} 时，变量赋值为 array或struct
				if( parser->prev_node && 
						parser->prev_node->type == EXP_NODE_TYPE_OPERTOR &&	
						parser->prev_node->oper->type == OPERTOR_TYPE_EVALUATION &&
						(parser->c_str->str[0] == '[' ||
						parser->c_str->str[0] == '{') ){

						node = struct_array_value_decode(parser);
						break;
				}

				node = script_calloc(1, sizeof(exp_node_t));
				node->type = EXP_NODE_TYPE_OPERTOR;
				node->oper = opertor_get(parser->c_str->str);
				if(node->oper == NULL){
					return -1;
				}
				break;
			case EXP_STRING_TYPE_PARENTHESIS:
				// 函数解析， 小括号前是字符串或']'时认为是函数
				if(parser->c_str->str[0] == '(' && 
						parser->cnode &&
						parser->c_str->prev && 
						(parser->c_str->prev->type == EXP_STRING_TYPE_STRING ||
						 parser->c_str->prev->str[0] == ']')) {

					exp_node_t *func_exp = NULL;
					exp_node_t *prev = NULL;
					exp_node_t *top = script_stack_Top(parser->stack);
					int priority = 1;
					int num = 1;
					int bracket_close = 0;
					while(top){
						//exp_node_print(top);
						if(top->type == EXP_NODE_TYPE_OPERTOR && top->oper->priority <= priority){
							if(top->oper->type == OPERTOR_TYPE_BRACKET_R){
								bracket_close = 1;
							}
							if(top->oper->type == OPERTOR_TYPE_BRACKET_L){
								if(bracket_close == 0){
									break;
								}
							}
							script_stack_Pop(parser->stack);
							if(func_exp == NULL){
								func_exp = top;
							}else{
								prev->next = top;
							}
							prev = top;
							priority = top->oper->priority;
							top = script_stack_Top(parser->stack);
							num++;
						}else{
							break;
						}
					}
					while(num > 0){
						exp_node_t *tmp = remove_end_exp(parser);
						if(tmp == NULL){
							SCRIPT_DEBUG_ERR("Function name parse fail");
							goto error;
						}
						if(tmp->type == EXP_NODE_TYPE_OPERTOR){
							num++;
						}else{
							num--;
						}
						if(func_exp == NULL){
							func_exp = tmp;
						}else{
							tmp->next = func_exp;
							func_exp = tmp;
						}
						prev = tmp;
					}

					node = exec_func_decode(parser,func_exp);
					parser->operator_flag = parser->prev_operator_flag;
				}else{
					node = exp_node_create(EXP_NODE_TYPE_OPERTOR,NULL);
					node->oper = opertor_get(parser->c_str->str);
					if(node->oper == NULL){
						return -1;
					}
				}
				
				break;
		}
		//printf("%s %d %s \n",__func__,__LINE__,parser->c_str->str);
		if(parser->c_str){	// 函数解析时c_str会等于NULL。
			parser->c_str = parser->c_str->next;
		}

		if (node == NULL) {
			return -1;
		}

		if (node->type == EXP_NODE_TYPE_OPERTOR) {
			if(parser->operator_flag == 1 && 
					node->oper->type != OPERTOR_TYPE_NOR &&
					node->oper->type != OPERTOR_TYPE_PARENTHESIS_L){
				SCRIPT_DEBUG_ERR("operator:'%s'. Expression syntax error!",node->oper->oper);
				return -1;

			}
			
			parser->prev_operator_flag = parser->operator_flag;
			parser->operator_flag = 1;
			while (!script_stack_IsEmpty(parser->stack)) {
				exp_node_t *top_node = script_stack_Top(parser->stack);
				//优先级低的在栈底
				if (node->oper->type == OPERTOR_TYPE_PARENTHESIS_R ||
						node->oper->type == OPERTOR_TYPE_BRACKET_R || 
						(top_node->oper->priority <= node->oper->priority))
				{
					if (top_node->oper->type == OPERTOR_TYPE_PARENTHESIS_L) {
						if (node->oper->type == OPERTOR_TYPE_PARENTHESIS_R) {
							script_stack_Pop(parser->stack);
							exp_node_destroy(top_node);
							pare_close = 1;
						}
						break;
					}

					if (top_node->oper->type == OPERTOR_TYPE_BRACKET_L) {
						if (node->oper->type == OPERTOR_TYPE_BRACKET_R) {
							script_stack_Pop(parser->stack);
							if (parser->exp_list == NULL) {
								parser->exp_list = top_node;
								parser->cnode = top_node;
							} else {
								parser->cnode->next = top_node;
								parser->cnode = top_node;
							}
							bracket_close = 1;
						}
						break;
					}

					script_stack_Pop(parser->stack);
					if (parser->exp_list == NULL) {
						parser->exp_list = top_node;
						parser->cnode = top_node;
					} else {
						parser->cnode->next = top_node;
						parser->cnode = top_node;
					}
				} else {
					break;
				}
			}
			if (node->oper->type != OPERTOR_TYPE_PARENTHESIS_R &&
					node->oper->type != OPERTOR_TYPE_BRACKET_R) {
				script_stack_Push(parser->stack, node);
				if(node->oper->type == OPERTOR_TYPE_PARENTHESIS_L){
					parser->pare_count++;
				}else if(node->oper->type == OPERTOR_TYPE_BRACKET_L){
					parser->bracket_count++;
				}
			}else if (node->oper->type == OPERTOR_TYPE_PARENTHESIS_R){
				parser->pare_count--;
				if(parser->pare_count < 0 && parser->exec_func_arg_flag == 0){
					SCRIPT_DEBUG_ERR("')' doesn't paired!");
					return -1;
				}
				exp_node_destroy(node);
				node = NULL;
				parser->prev_operator_flag = parser->operator_flag;
				parser->operator_flag = 0;
				if(pare_close == 0){
					if(parser->c_str){
						parser->c_str = parser->c_str->prev;
					}
					exp_node_destroy(node);
					goto end;
				}else{
					pare_close = 0;
				}
			}else if (node->oper->type == OPERTOR_TYPE_BRACKET_R){
				parser->bracket_count--;
				if(parser->bracket_count < 0){
					SCRIPT_DEBUG_ERR("Bracket isn't pair! ']'  ");
					goto error;
				}
				if(bracket_close == 0){
					SCRIPT_DEBUG_ERR("Bracket isn't pair! '['  ");
					goto error;
				}else{
					bracket_close = 0;
				}
				parser->prev_operator_flag = parser->operator_flag;
				parser->operator_flag = 0;
				exp_node_destroy(node);
				node = NULL;
			}else{
				exp_node_destroy(node);
				node = NULL;
			}
		} else {
			if(parser->operator_flag == 2){
				SCRIPT_DEBUG_ERR("Expression syntax error!");
				goto error;
			}
			parser->prev_operator_flag = parser->operator_flag;
			parser->operator_flag = 2;
			if (parser->exp_list == NULL) {
				parser->exp_list = node;
				parser->cnode = node;
			} else {
				parser->cnode->next = node;
				parser->cnode = node;
			}
		}
		parser->prev_node = node;
	}

end:
	while (!script_stack_IsEmpty(parser->stack)) {
		exp_node_t *top_node = script_stack_Pop(parser->stack);
		if (top_node->oper->type == OPERTOR_TYPE_PARENTHESIS_L) {
			exp_node_destroy(top_node);
			continue;
		}

		if(parser->exp_list == NULL){
			parser->exp_list = top_node;
			parser->cnode = top_node;
		}else{
			parser->cnode->next = top_node;
			parser->cnode = top_node;
		}
		parser->flag = 2;
	}

	if(parser->pare_count > 0){
		SCRIPT_DEBUG_ERR("'(' doesn't paired!");
		return SCRIPT_ERR_SYNTAX;
	}
	if(parser->bracket_count > 0){
		SCRIPT_DEBUG_ERR("'[' doesn't paired!");
		return SCRIPT_ERR_SYNTAX;
	}

	return ret;

error:
	return -1;
}

static exp_node_t *exec_func_decode(exp_parser_t *parser,exp_node_t *func_exp)
{
	if(parser == NULL){
		return NULL;
	}

	exec_func_t *ex_func = script_func_node_create();
	if(ex_func == NULL){
		return NULL;
	}

	ex_func->type = 1;
	ex_func->exp = func_exp;

	exp_parser_t arg_parser = {0};

	if(parser->c_str->str[0] != '('){
		goto err;
	}

	parser->c_str = parser->c_str->next;


	while(parser->c_str){
		if(parser->c_str->str[0] == ')'){
			break;
		}
		memset(&arg_parser,0,sizeof(arg_parser));
		arg_parser.script = parser->script;
		arg_parser.strs = parser->c_str;
		arg_parser.c_str = parser->c_str;
		arg_parser.stack = script_stack_create(1);
		arg_parser.exec_func_arg_flag = 1;
		if(expression_str(&arg_parser) < 0){
			// TODO  error handle
			goto err;
		}else{
			TFly_list_add(ex_func->args,arg_parser.exp_list);
			arg_parser.exp_list = NULL;
		}

		parser->c_str = arg_parser.c_str;
		script_stack_destroy(arg_parser.stack);
		arg_parser.stack = NULL;
	}



	if(arg_parser.stack){
		script_stack_destroy(arg_parser.stack);
	}

	exp_node_t *exp = exp_node_create(EXP_NODE_TYPE_FUNC,ex_func);
	if(exp == NULL){
		// TODO error handle
	}

	exp->func = ex_func;

	return exp;


err:
	// TODO error handle destroy resource
	if(arg_parser.stack){
		script_stack_destroy(arg_parser.stack);
	}
	SCRIPT_DEBUG_ERR("exec_func_decode fail");
	return NULL;
}


/********************************************************
 *	function:	expression_decode
 *				analysis expression from string.
 *	@str:		expression string.
 *	@script:	expression所属的script。主要用于
 *				获取表达式中的变量。
 *				
 * ******************************************************/
exp_node_t *expression_decode(exp_string_t *exp_str, script_t *script)
{
	if (exp_str == NULL) {
		return NULL;
	}

	script_stack_t *stack = script_stack_create(1);

	exp_parser_t parser = {0};
	parser.stack = stack;
	parser.strs = exp_str;
	parser.c_str = exp_str;
	parser.script = script;

	int ret = 0;
	do{
		ret = expression_str(&parser);
	}while(ret == 1);

	if(ret < 0){
		goto error;
	}

	//exp_list_print(head);
	script_stack_destroy(stack);
	return parser.exp_list;
error:
	// TODO 
	script_stack_force_destroy(stack);
	if (parser.exp_list) {
		exp_node_list_destroy(parser.exp_list);
	}
	return NULL;
}

exp_node_t *expression_parse(char *code, script_t *script)
{
	exp_string_t *string = exp_string_decode(code);	
	if(string == NULL){
		return NULL;
	}

	exp_node_t *exp = expression_decode(string,script);
	exp_string_destroy(string);
	return exp;
}


exp_node_t *func_calc(exp_node_t *exp,script_stack_t *block_stack)
{
	exec_func_t *exec = exp->func;
	exp_node_t *result = NULL;
	exp_var_t *_result = NULL;
	exp_func_t *func = NULL;
	if(exec->type == 1){
		result = expression_calc(exec->exp,block_stack);
		if(result == NULL || result->type != EXP_NODE_TYPE_VAR){
			exp_node_destroy(result);
			SCRIPT_DEBUG_ERR("Function run fail,can't find function!");
			return NULL;
		}
		_result = exp_var_point_take(result->var);
		if(_result == NULL || _result->type != EXP_VAR_TYPE_FUNCTION){
			exp_node_destroy(result);
			SCRIPT_DEBUG_ERR("Function run fail, var isn't function!");
			return NULL;
		}
		func = _result->func->func;
		exp_node_destroy(result);
	}else{
		func = exec->func;
	}


	if(func->type == EXEC_FUNC_TYPE_C){
		result = func->c_func->func(exec->args,block_stack,func->c_func->param);
	}else{
		// 创建函数参数变量加入到函数的执行block中
		exp_node_t *arg = TFly_list_get_first(func->s_func->args);		// 函数参数列表
		exp_node_t *in_arg = TFly_list_get_first(exec->args);	// 执行函数传入参数
		exp_var_t *vars = exp_var_create("this");
		vars->type = EXP_VAR_TYPE_STRUCT;
		while(arg){
			exp_node_t *result = NULL;
			if(in_arg){
				result = expression_calc(in_arg,block_stack);	// 计算入参表达式
				if(result == NULL || result->type == EXP_NODE_TYPE_ERR){
					SCRIPT_DEBUG_ERR("func_calc arg calc fail");
					goto err;
				}
			}else{
				result = exp_node_create(EXP_NODE_TYPE_CONST_NULL,NULL);
			}


			exp_var_t *var = exp_var_create(arg->string);

			if(result->type == EXP_NODE_TYPE_VAR){ // 入参为结构体或数组 函数时 传入指针
				if(result->var->type == EXP_VAR_TYPE_POINT ||
						result->var->type == EXP_VAR_TYPE_FUNCTION ||
						result->var->type == EXP_VAR_TYPE_ARRAY ||
						result->var->type == EXP_VAR_TYPE_STRUCT){
					var->type = EXP_VAR_TYPE_POINT;
					var->var = exp_var_refer(exp_var_point_take(result->var));
				}else{
					exp_var_copy(result->var,var);
					//var->name = script_calloc(1,strlen(arg->string) + 1);
					//strcpy(var->name,arg->string);
					//result->var = NULL;
				}
			}else{
				exp_var_t *tmp_var = exp_var_create(NULL);
				tmp_var->type = EXP_VAR_TYPE_POINT;
				tmp_var->var = exp_var_refer(var);
				exp_node_t *left = exp_node_create(EXP_NODE_TYPE_VAR,tmp_var);
				
				extern exp_node_t *evaluation(exp_node_t *left, exp_node_t *right);
				exp_node_t *result1 = evaluation(left,result);	// 给参数变量赋值
				exp_node_destroy(result1);
				exp_node_destroy(left);
			}

			exp_node_destroy(result);

			//printf("result1:");
			//exp_node_print(result1);
			//show_exp_var(var,2);


			//exp_var_struct_add(func->s_func->block->vars,var);
			exp_var_struct_add(vars,var);


			in_arg = TFly_list_get_next(exec->args);
			arg = TFly_list_get_next(func->s_func->args);
		}

		script_stack_t *stack = script_stack_create(0);
		//script_stack_Push(stack,func->s_func->exec_block);
		script_stack_Push(stack,_result->func->block);
		result = run_block(func->s_func->block,stack,vars);

		//result = run_block(func->s_func->block,block_stack,vars);
		if(result == NULL){
			SCRIPT_DEBUG_ERR("Block run result is NULL");
			script_stack_destroy(stack);
			goto err;
		}

		script_stack_destroy(stack);

		if(result->ctrl == EXP_NODE_CTRL_CONTINUE){
			SCRIPT_DEBUG_ERR("Function exec error. The continue is not in while");
		}else if(result->ctrl == EXP_NODE_CTRL_BREAK){
			SCRIPT_DEBUG_ERR("Function exec error. The break is not in while");
		}
		result->ctrl = EXP_NODE_CTRL_NONE;
		//exp_node_print(result);
	}


	return result;
err:
	if(result){
		if(result->type == EXP_NODE_TYPE_ERR){
			return result;
		}
		exp_node_destroy(result);
	}
	return NULL;
}


/********************************************************
 *	function:	expression_calc
 *				calculate expression, return the result.
 *	@exp:		expression 
 *	
 *	@return:	expression calculate result. Result node type 
 *				is EXP_NODE_TYPE_INT or EXP_NODE_TYPE_STRING.
 *				The result need call exp_node_destroy to 
 *				release.
 *				
 * ******************************************************/
exp_node_t *expression_calc(exp_node_t *exp, script_stack_t *block_stack)
{
	if (exp == NULL) {
		SCRIPT_DEBUG_ERR("param error");
		return NULL;
	}

	//printf("%s %d\r\n",__func__,__LINE__);
	//exp_list_print(exp);
	script_stack_t *stack = script_stack_create(1);
	script_stack_t *result_stack = script_stack_create(1);	// 用于记录中间结果，便于最后销毁
	exp_node_t *node = exp;
	exp_node_t *left, *right, *result, *tmp;
	while (node) {
		if (node->type == EXP_NODE_TYPE_OPERTOR) {
			right = script_stack_Pop(stack);
			// 单目运算符
			if(node->oper->type == OPERTOR_TYPE_NOR ||	
					node->oper->type == OPERTOR_TYPE_BITNOR){
				left = NULL;
			}else{ // 双目运算符
				left = script_stack_Pop(stack);
			}
			result = node->oper->calc(left, right);
			if (result == NULL)
				break;

			script_stack_Push(result_stack, result);
			script_stack_Push(stack, result);
			if(result->type == EXP_NODE_TYPE_ERR){
				break;
			}
		} else if (node->type == EXP_NODE_TYPE_FUNC) {
			result = func_calc(node,block_stack);
			if (result == NULL){
				goto exit;
			}

			script_stack_Push(result_stack, result);
			script_stack_Push(stack, result);
			if(result->type == EXP_NODE_TYPE_ERR){
				break;
			}
		} else if (node->type == EXP_NODE_TYPE_VAR_NAME) {
			exp_var_t *var = script_var_find(block_stack,node->var_name);
			if(var == NULL){
				SCRIPT_DEBUG_ERR("exp calc fail, Can't find var %s",node->var_name);
				return exp_node_create(EXP_NODE_TYPE_ERR,NULL);
			}
			tmp = exp_node_create(EXP_NODE_TYPE_VAR,NULL);
			tmp->var = exp_var_refer(var);

			script_stack_Push(stack,tmp);
			script_stack_Push(result_stack,tmp);
		} else {
			script_stack_Push(stack, node);
		}
		node = node->next;
	}

	result = script_calloc(1, sizeof(exp_node_t));
	if (!script_stack_IsEmpty(stack)) {
		tmp = script_stack_Pop(stack);
		if (tmp->type == EXP_NODE_TYPE_VAR) {
			result->type = EXP_NODE_TYPE_VAR;
			result->var = exp_var_refer(exp_var_point_take(tmp->var));
			result->ctrl = tmp->ctrl;
		} else {
			exp_node_copy(result, tmp);
		}
	}

exit:
	while (!script_stack_IsEmpty(result_stack)) {
		tmp = script_stack_Pop(result_stack);
		exp_node_destroy(tmp);
	}

	script_stack_destroy(result_stack);
	script_stack_destroy(stack);

	return result;
}

void show_exp_string_t(struct exp_string_t *exp)
{
	char type[32] = {0};

	printf("***** expression string spilt *****\n");
	while (exp)
	{
		memset(type, 0, sizeof(type));
		switch (exp->type)
		{
		case EXP_STRING_TYPE_NONE:
			strcpy(type, "unKnow");
			break;
		case EXP_STRING_TYPE_NUMBER:
			strcpy(type, "number");
			break;
		case EXP_STRING_TYPE_STRING:
			strcpy(type, "string");
			break;
		case EXP_STRING_TYPE_OPERTOR:
			strcpy(type, "operator");
			break;
		case EXP_STRING_TYPE_PARENTHESIS:
			strcpy(type, "parenthesis");
			break;
		}
		printf(" %-8s %s\n", type, exp->str);
		exp = exp->next;
	}
}

exp_node_t *exp_node_create(exp_node_type_e type, void *value)
{
	exp_node_t *node = script_calloc(1,sizeof(exp_node_t));
	if(node == NULL){
		return NULL;
	}
	//printf("\033[32m%s %d node:%p type:%d\033[0m\r\n",__func__,__LINE__,node,type);

	node->type = type;
	switch(type){
		case EXP_NODE_TYPE_CONST_INT:
			node->number = (int)value;
			break;
		case EXP_NODE_TYPE_CONST_DOUBLE:
			node->d = *(double*)value;
			break;
		case EXP_NODE_TYPE_CONST_STRING:
			if(value){
				node->string = script_calloc(1,strlen(value)+1);
				strcpy(node->string,value);
			}
			break;
		case EXP_NODE_TYPE_VAR:
			node->var = value;
			break;
		case EXP_NODE_TYPE_VAR_NAME:
			if(value){
				node->var_name = script_calloc(1,strlen(value)+1);
				strcpy(node->var_name,value);
			}
			break;
		case EXP_NODE_TYPE_FUNC:
			node->func = value;
			break;
		default:
			break;
	}
	return node;
}

void exp_node_destroy(exp_node_t *node)
{
	if (node == NULL) {
		return;
	}

	//printf("%s %d node_type:%d %p\n",__func__,__LINE__,node->type,node);
	if (node->type == EXP_NODE_TYPE_CONST_STRING && node->string) {
		script_free(node->string);
	}else if(node->type == EXP_NODE_TYPE_FUNC && node->func){
		script_func_node_destroy(node->func);
	}else if(node->type == EXP_NODE_TYPE_VAR_NAME && node->var_name){
		script_free(node->var_name);
	}else if(node->type == EXP_NODE_TYPE_VAR && node->var){
		exp_var_destroy(node->var);
	}

	script_free(node);
}

void exp_node_list_destroy(exp_node_t *node)
{
	if(node == NULL){
		return;
	}

	exp_node_t *n = node;
	exp_node_t *c;
	while (n) {
		c = n->next;
		exp_node_destroy(n);
		n = c;
	}
}

void exp_node_print(exp_node_t *node)
{
	if (node == NULL) {
		return;
	}
	switch (node->type) {
		case EXP_NODE_TYPE_CONST_INT:
			printf("int       %d\n", node->number);
			break;
		case EXP_NODE_TYPE_CONST_STRING:
			printf("string    %s\n", node->string);
			break;
		case EXP_NODE_TYPE_VAR:
			printf("var       %s %d\n",node->var->name,node->var->type);
			show_exp_var(node->var,0);
			break;
		case EXP_NODE_TYPE_OPERTOR:
			printf("opertor   %s\n", node->oper->oper);
			break;
		case EXP_NODE_TYPE_VAR_NAME:
			printf("var_name %s\n", node->var_name);
			break;
		case EXP_NODE_TYPE_FUNC:
			printf("function \n");
			break;
		case EXP_NODE_TYPE_CONST_NULL:
			printf("CONST NULL\n");
			break;
		default:
			printf("Unknow node type\n");
			break;
	}
}

void exp_list_print(exp_node_t *head)
{
	printf("****exp list printf--------------------------\n ");
	exp_node_t *node = head;
	while (node) {
		exp_node_print(node);
		node = node->next;
	}
}

char *exp_node_to_string(exp_node_t *node)
{
	if(node == NULL){
		return NULL;
	}

	char *buf = NULL;
	switch (node->type) {
		case EXP_NODE_TYPE_CONST_INT:
			buf = script_calloc(1,32);
			sprintf(buf,"%d", node->number);
			break;
		case EXP_NODE_TYPE_CONST_DOUBLE:
			buf = script_calloc(1,128);
			sprintf(buf,"%f", node->d);
			break;
		case EXP_NODE_TYPE_CONST_STRING:
			buf = script_calloc(1,strlen(node->string)+1);
			sprintf(buf,"%s", node->string);
			break;
		case EXP_NODE_TYPE_CONST_NULL:
			buf = script_calloc(1,8);
			sprintf(buf,"NULL");
			break;
		case EXP_NODE_TYPE_CONST_TRUE:
			buf = script_calloc(1,8);
			sprintf(buf,"TRUE");
			break;
		case EXP_NODE_TYPE_CONST_FALSE:
			buf = script_calloc(1,8);
			sprintf(buf,"FALSE");
			break;
		case EXP_NODE_TYPE_VAR:
			return exp_var_print(node->var);
		default:
			printf("Unknow node type\n");
			break;
	}

	return buf;
}

